﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Interop;
using System.Runtime.InteropServices;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Shapes;

namespace Addins.UI.Windows
{
    /// <summary>
    /// The base for windows that don't allow closing by using the system menu
    /// </summary>
    public class WindowBase : Window
    {
        #region Instance Fields (Private)

        private bool allowClosing = false;
        private List<DependencyObject> hitTestResults = new List<DependencyObject>();

        #endregion

        #region Constructor

        public WindowBase()
        {
            // Set the font to use in all derived windows
            this.FontFamily = new System.Windows.Media.FontFamily("Segoe UI");

            // Allow moving the window by clicking on the caption area 
            // (the Rectangle shape all derived windows have at their top)
            this.MouseDown += (sender, e) =>
            {
                this.hitTestResults.Clear();

                VisualTreeHelper.HitTest(
                    this,
                    null,
                    new HitTestResultCallback(this.GatherHitTestResults),
                    new PointHitTestParameters(e.GetPosition(this)));
                if (hitTestResults.Count > 0)
                {
                    this.DragMove();
                }
            };
        }

        public HitTestResultBehavior GatherHitTestResults(HitTestResult result)
        {
            // Add the hit test result to the list that will be processed after the enumeration.
            if (result.VisualHit is Rectangle)
            {
                this.hitTestResults.Add(result.VisualHit);
            }

            // Set the behavior to return visuals at all z-order levels.
            return HitTestResultBehavior.Continue;
        }

        #endregion

        #region Overrides

        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);

            HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;

            if (hwndSource != null)
            {
                hwndSource.AddHook(this.HwndSourceHook);
            }
        }

        #endregion

        #region Instance Methods (Protected)

        protected void ForceClose()
        {
            this.allowClosing = true;
            this.Close();
        }

        #endregion

        #region Instance Methods (Private)

        private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            {
                case WM_SHOWWINDOW:
                    {
                        IntPtr hMenu = WindowBase.GetSystemMenu(hwnd, false);
                        if (hMenu != IntPtr.Zero)
                        {
                            WindowBase.EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
                        }
                    }
                    break;
                case WM_CLOSE:
                    if (!allowClosing)
                    {
                        handled = true;
                    }
                    break;
            }
            return IntPtr.Zero;
        }

        #endregion

        #region P/Invoke declarations

        [DllImport("user32.dll")]
        private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
        [DllImport("user32.dll")]
        private static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);

        private const uint MF_BYCOMMAND = 0x00000000;
        private const uint MF_GRAYED = 0x00000001;
        private const uint SC_CLOSE = 0xF060;
        private const int WM_SHOWWINDOW = 0x00000018;
        private const int WM_CLOSE = 0x10;

        #endregion
    }
}
